﻿using Gameplay.PVE;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using Yoozoo.Core.Extensions.CSharp;

namespace Yoozoo.Modules.Furnitures.Editor
{
    [CustomEditor(typeof(Room))]
    public class RoomEditor : UnityEditor.Editor
    {
        private Room room;
        private Vector3 _pointInGrid;

        /// <summary>
        /// 0: 添加新的点
        /// 1：移动旧的点
        /// </summary>
        private int status = 0;

        private int selectedPointIndex = 0;

        private Vector3 selectedPoint;


        void OnEnable()
        {
            room = (Room)this.target;
        }
        
        void OnSceneGUI()
        {
            HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));
            int id = GUIUtility.GetControlID(FocusType.Passive);
            EventType type = Event.current.GetTypeForControl(id);
            
            if (room == null || room.Planes.IsEmpty())
            {
                return;
            }
            
            if (type == EventType.MouseMove)
            {
                Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);

                var roomPlane = room.GetSelectedPlane();
                var plan = roomPlane.GetPlane();
                if (plan.Raycast(ray, out float distance))
                {
                    var point = ray.GetPoint(distance);
                    var pointCoordinate = roomPlane.OriginPoint.InverseTransformPoint(point);
                    pointCoordinate.x = Mathf.Round(pointCoordinate.x * 2) * 0.5f;
                    pointCoordinate.y = 0;
                    pointCoordinate.z = Mathf.Round(pointCoordinate.z * 2) * 0.5f;

                    _pointInGrid = roomPlane.OriginPoint.TransformPoint(pointCoordinate);
                }
            }

            if (type == EventType.Repaint)
            {
                Handles.SphereHandleCap(0, _pointInGrid, Quaternion.identity, 0.2f, EventType.Repaint);
                var roomPlane = room.GetSelectedPlane();
                if (status == 0)
                {
                    if (roomPlane.Polygon.Contains(_pointInGrid))
                    {
                        Handles.Label(_pointInGrid + Vector3.right, "点击左键编辑");
                    }
                    else
                    {
                        Handles.Label(_pointInGrid + Vector3.right, "点击左键添加");
                    }
                }
                else if (status == 1)
                {
                    roomPlane.Polygon[selectedPointIndex] = _pointInGrid;
                    Handles.Label(_pointInGrid + Vector3.right, "点击右键删除，左键确认, 中键退出");
                }
            }

            if (type == EventType.MouseDown )
            {
                var roomPlane = room.GetSelectedPlane();
                if (status == 0 && Event.current.button == 0)
                {
                    if (roomPlane.Polygon.Contains(_pointInGrid))
                    {
                        status = 1;
                        selectedPointIndex = roomPlane.Polygon.IndexOf(_pointInGrid);
                        selectedPoint = _pointInGrid;
                    }
                    else
                    {
                        roomPlane.AddPoint(_pointInGrid);
                    }
                }
                else if (status == 1)
                {
                    if (Event.current.button == 0)
                    {
                        // 左键确认
                        status = 0;
                        roomPlane.Polygon[selectedPointIndex] = _pointInGrid;
                    }
                    else if (Event.current.button == 2)
                    {
                        // 中间复原， 退出
                        status = 0;
                        roomPlane.Polygon[selectedPointIndex] = selectedPoint;
                    }
                    else if (Event.current.button == 1)
                    {
                        // 右键
                        status = 0;
                        roomPlane.Polygon.RemoveAt(selectedPointIndex);
                        EditorUtility.SetDirty(room);
                    }
                }
            }

            HandleUtility.Repaint();
        }

        public override void OnInspectorGUI()
        {
            GUILayout.Label("房间编辑器");
            if (GUILayout.Button("创建地板"))
            {
                room.CreatePlane();
            }
            if (GUILayout.Button("创建墙体"))
            {
                room.MakeWalls();
            }
            if (GUILayout.Button("复制当前平面"))
            {
                var plane = room.GetSelectedPlane();
                room.Copy(plane);

                room.SelectedPlaneIndex = room.Planes.Count - 1;
                EditorUtility.SetDirty(room);
            }

            if (GUILayout.Button("翻转当前平面"))
            {
                var plane = room.GetSelectedPlane();
                plane.Flip();
            }

            if (!room.Planes.IsEmpty() && room.SelectedPlaneIndex > 0)
            {
                if (GUILayout.Button("删除当前平面"))
                {
                    room.RemoveSelectedPlane();
                }
            }

            if (GUILayout.Button("收集光照信息"))
            {
                Collect(room.RoomSceneConfig, room.RoomId, room.transform.parent);
                EditorUtility.SetDirty(room);
                AssetDatabase.Refresh();
            }

            if (GUILayout.Button("保存房间信息"))
            {
                SaveRoomInfo();
            }

            string[] toolbar = new string[room.Planes.Count];
            for (int i = 0; i < room.Planes.Count; i++)
            {
                toolbar[i] = i.ToString();
            }
            room.SelectedPlaneIndex = GUILayout.Toolbar(room.SelectedPlaneIndex, toolbar);

            //m_isEdit = GUILayout.Toggle(m_isEdit, "Edit");

            DrawDefaultInspector();
        }

        private void SaveRoomInfo()
        {
            int roomId = room.RoomId;
            string luaPath = Path.Combine("Lua/modules/room/Config", $"Room{roomId:D2}.lua");

            using (StreamWriter streamWriter = new StreamWriter(File.Open(luaPath, FileMode.Create)))
            {
                streamWriter.WriteLine("---@type RoomInfo");
                streamWriter.WriteLine("local Room = {");
                var assetPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(room);
                streamWriter.WriteLine($"    PrefabPath = \"{assetPath}\",");

                streamWriter.WriteLine("    SceneRenderData = {");

                var renderData = room.RoomSceneConfig.RenderData;
                // lightMap
                streamWriter.WriteLine($"        lightMapCount = {renderData.lightMapColorPath.Count},");
                streamWriter.WriteLine("        lightMapColor = {");
                foreach (var path in renderData.lightMapColorPath)
                {
                    streamWriter.WriteLine($"            \"{path}\",");
                }
                streamWriter.WriteLine("        },");
                streamWriter.WriteLine("        lightMapDir = {");
                foreach (var path in renderData.lightMapDirPath)
                {
                    streamWriter.WriteLine($"            \"{path}\",");
                }
                streamWriter.WriteLine("        },");

                // fog 
                var isFog = renderData.isFog ? "true" : "false";
                streamWriter.WriteLine($"        isFog = {isFog},");
                var fogColor = $"Color.New({renderData.fogColor.r}, {renderData.fogColor.g}, {renderData.fogColor.b}, {renderData.fogColor.a})";
                streamWriter.WriteLine($"        fogColor = {fogColor},");
                streamWriter.WriteLine($"        fogStart = {renderData.fogStart},");
                streamWriter.WriteLine($"        fogEnd = {renderData.fogEnd},");
                streamWriter.WriteLine($"        fogMode = {(int)renderData.fogMode},");

                // skyBox
                streamWriter.WriteLine($"        skyBoxMaterialPath = \"{renderData.skyBoxMaterialPath}\",");

                // other
                var ambientColor = $"Color.New({renderData.ambientColor.r}, {renderData.ambientColor.g}, {renderData.ambientColor.b}, {renderData.ambientColor.a})";
                streamWriter.WriteLine($"        ambientColor = {ambientColor},");
                streamWriter.WriteLine($"        ambientMode = {(int)renderData.ambientMode},");
                streamWriter.WriteLine($"        reflectionMode = {(int)renderData.reflectionMode},");

                // reflection probe
                streamWriter.WriteLine($"        reflectionProbePath = \"{renderData.reflectionProbePath}\",");

                streamWriter.WriteLine("    },");

                streamWriter.WriteLine("    MeshRendererData = {");
                var meshRendererPaths = room.RoomSceneConfig.MeshRendererPaths;
                var meshRendererData = room.RoomSceneConfig.MeshRendererData;
                foreach (var data in meshRendererData)
                {
                    streamWriter.WriteLine("        {");
                    streamWriter.WriteLine($"            Path = \"{meshRendererPaths[data.renderIndex]}\",");
                    streamWriter.WriteLine($"            LightmapIndex = {data.lightmapIndex},");
                    var lightmapScaleOffset = $"Vector4.New({data.lightmapScaleOffset.x}, {data.lightmapScaleOffset.y}, {data.lightmapScaleOffset.z}, {data.lightmapScaleOffset.w})";
                    streamWriter.WriteLine($"            lightmapScaleOffset = {lightmapScaleOffset},");
                    streamWriter.WriteLine("        },");
                }

                streamWriter.WriteLine("    },");

                streamWriter.WriteLine("    Planes = {},");
                streamWriter.WriteLine("}");
                streamWriter.WriteLine();
                streamWriter.WriteLine("-- 不可放置家具");
                streamWriter.WriteLine("-- 墙纸");
                streamWriter.WriteLine("Room.Wallpaper = {");
                streamWriter.WriteLine($"    defaultFurnitureId = {room.WallpaperId},");
                streamWriter.WriteLine($"    furnitureId = {room.WallpaperId},");
                streamWriter.WriteLine("}");
                streamWriter.WriteLine();
                streamWriter.WriteLine("-- 地砖");
                streamWriter.WriteLine("Room.FloorTile = {");
                streamWriter.WriteLine($"    defaultFurnitureId = {room.FloorTileId},");
                streamWriter.WriteLine($"    furnitureId = {room.FloorTileId},");
                streamWriter.WriteLine("}");
                streamWriter.WriteLine();

                streamWriter.WriteLine("-- 地面, 墙面和天花板");
                int count = room.Planes.Count;
                for (int i = 0; i < count; i++)
                {
                    int planeId = i + 1;
                    var plane = room.Planes[i];

                    streamWriter.WriteLine($"Room.Planes[{planeId}] = {{");
                    //streamWriter.WriteLine("    Type = E_PLANE_TYPE.Floor,");

                    var position = plane.OriginCoordinate;
                    streamWriter.WriteLine($"    Type = E_PLANE_TYPE.{plane.PlaneType},");
                    streamWriter.WriteLine("    Position = {");
                    streamWriter.WriteLine($"        x = {position.x},");
                    streamWriter.WriteLine($"        y = {position.y},");
                    streamWriter.WriteLine($"        z = {position.z},");
                    streamWriter.WriteLine("    },");

                    var eulerAngles = plane.OriginPoint.eulerAngles;
                    streamWriter.WriteLine("    EulerAngles = {");
                    streamWriter.WriteLine($"        x = {eulerAngles.x},");
                    streamWriter.WriteLine($"        y = {eulerAngles.y},");
                    streamWriter.WriteLine($"        z = {eulerAngles.z},");
                    streamWriter.WriteLine("    },");

                    streamWriter.WriteLine("    Size = {");
                    streamWriter.WriteLine($"        x = {plane.Length},");
                    streamWriter.WriteLine($"        y = {plane.Width},");
                    streamWriter.WriteLine("    },");

                    streamWriter.WriteLine("    ValidArea = {");
                    var polygon = plane.Polygon;
                    foreach (var point in polygon)
                    {
                        var pointInPlane = plane.OriginPoint.InverseTransformPoint(point);
                        streamWriter.WriteLine($"        {{ x = {pointInPlane.x}, y = {pointInPlane.z}}},");
                    }

                    streamWriter.WriteLine("    },");
                    streamWriter.WriteLine("}");
                    streamWriter.WriteLine();
                }

                streamWriter.WriteLine("return Room");
            }

            EditorUtility.DisplayDialog("保存房间信息", "保存完毕, 保存至: \n" + luaPath, "确定");
        }

        private const string AssetRootPath = "Assets/ResourcesAssets/Prefabs/Furniture/Room";

        public void Collect(RoomSceneConfig sceneConfig, int roomId, Transform rootTransform)
        {
            CollectMeshRenderData(sceneConfig, rootTransform);
            CollectRenderData(sceneConfig, roomId);
        }

        public void CollectMeshRenderData(RoomSceneConfig sceneConfig, Transform rootTransform)
        {
            if (rootTransform == null)
                return;

            sceneConfig.MeshRendererData.Clear();
            sceneConfig.MeshRendererPaths.Clear();

            var renderers = rootTransform.GetComponentsInChildren<MeshRenderer>(true);

            if (renderers == null)
                return;

            int renderIndex = 0;
            for (int i = 0; i < renderers.Length; i++)
            {
                var renderer = renderers[i];
                if (renderer.lightmapIndex >= 0)
                {
                    var rendererData = new MeshRendererData
                    {
                        lightmapIndex = renderer.lightmapIndex,
                        lightmapScaleOffset = renderer.lightmapScaleOffset,
                        renderIndex = renderIndex
                    };
                    sceneConfig.MeshRendererData.Add(rendererData);
                    var path = GetPath(renderer.transform, rootTransform);
                    sceneConfig.MeshRendererPaths.Add(path);

                    renderIndex++;
                }
            }
        }

        protected string GetPath(Transform t, Transform root = null)
        {
            var path = t.name;
            while (t.parent != root)
            {
                path = t.parent.name + "/" + path;
                t = t.parent;
            }

            return path;
        }

        protected void MakeSureDirectoryExists(string path)
        {
            string directory = Path.GetDirectoryName(path);
            if (string.IsNullOrEmpty(directory))
                return;

            if (Directory.Exists(directory))
                return;

            Directory.CreateDirectory(directory);
        }

        public void CollectRenderData(RoomSceneConfig sceneConfig, int roomId)
        {
            SceneRenderData renderData = sceneConfig.RenderData;

            // lightMap
            List<string> lightMapPaths = new List<string>();
            for (int i = 0; i < LightmapSettings.lightmaps.Length; i++)
            {
                string mapPath = $"{AssetRootPath}/Textures/tex_{roomId}_{i}_comp_light.tga";
                var path = AssetDatabase.GetAssetPath(LightmapSettings.lightmaps[i].lightmapColor);
                MakeSureDirectoryExists(mapPath);
                AssetDatabase.CopyAsset(path, mapPath);
                lightMapPaths.Add(mapPath);
            }
            renderData.lightMapColorPath = new List<string>();
            renderData.lightMapColorPath.AddRange(lightMapPaths);

            List<string> lightMapDirPaths = new List<string>();
            for (int i = 0; i < LightmapSettings.lightmaps.Length; i++)
            {
                string mapPath = $"{AssetRootPath}/Textures/tex_{roomId}_{i}_comp_dir.png";
                var path = AssetDatabase.GetAssetPath(LightmapSettings.lightmaps[i].lightmapDir);
                MakeSureDirectoryExists(mapPath);
                AssetDatabase.CopyAsset(path, mapPath);
                lightMapDirPaths.Add(mapPath);
            }
            renderData.lightMapDirPath = new List<string>();
            renderData.lightMapDirPath.AddRange(lightMapDirPaths);

            // fog 
            renderData.isFog = RenderSettings.fog;
            renderData.fogColor = RenderSettings.fogColor;
            renderData.fogStart = RenderSettings.fogStartDistance;
            renderData.fogEnd = RenderSettings.fogEndDistance;
            renderData.fogMode = RenderSettings.fogMode;

            // skyBox
            var skyBoxMat = Object.Instantiate(RenderSettings.skybox);
            var skyBoxMatPath = $"{AssetRootPath}/Materials/mat_{roomId}_skyBox.mat";
            MakeSureDirectoryExists(skyBoxMatPath);
            AssetDatabase.CreateAsset(skyBoxMat, skyBoxMatPath);
            renderData.skyBoxMaterialPath = skyBoxMatPath;

            // other
            renderData.ambientColor = RenderSettings.ambientLight;
            renderData.ambientMode = RenderSettings.ambientMode;
            renderData.reflectionMode = RenderSettings.defaultReflectionMode;

            // reflection probe
            var lightingDataPath = AssetDatabase.GetAssetPath(Lightmapping.lightingDataAsset);
            var reflectProbePath = lightingDataPath.Replace("LightingData.asset", "ReflectionProbe-0.exr");
            if (File.Exists(reflectProbePath))
            {
                var reflectProbeNewPath = $"{AssetRootPath}/Textures/tex_{roomId}_reflection_probe.exr";
                renderData.reflectionProbePath = reflectProbeNewPath;
                MakeSureDirectoryExists(reflectProbeNewPath);
                AssetDatabase.CopyAsset(reflectProbePath, reflectProbeNewPath);
            }
        }

    }
}
